package com.example.paopao.consumer.memer.config;

import com.alibaba.fastjson.JSON;
import com.example.paopao.common.enumerator.ServiceCode;
import com.example.paopao.common.web.JsonResult;
import com.example.paopao.consumer.memer.filter.JwtAuthorizationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.PrintWriter;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthorizationFilter jwtAuthorizationFilter;

    /*
    * BCryptPasswordEncoder属于密码编码器类（PasswordEncoder），
    * 用于将密码进行哈希处理和加密。它使用bcrypt密码散列算法，
    * 是Spring Security框架中常用的密码编码器之一。
    * 通过使用适当的哈希算法和加盐技术，BCryptPasswordEncoder可以提供较高的数据安全性。
    * */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //启用spring security内置的corsFilter,允许跨域访问
        http.cors();

        //启用Spring security创建Session的策略，配置为：不使用session
        /*
        * 关于取值：
        * -- NEVER：从不主动创建Session，但是，如果Session已存在，将会使用
        * -- STAELESS：无状态的，永不使用Session保存客户端的状态
        * */
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        //将解析JWT的过滤器，配置在Spring Security的相关过滤器之前
        http.addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class);

        /*处理需要认证尚未铜鼓认证的问题*/
        http.exceptionHandling().authenticationEntryPoint((httpServletRequest, httpServletResponse, e) -> {
           String message="您当前未登录，请先登录！";
            JsonResult jsonResult = JsonResult.fail(ServiceCode.ERROR_UNAUTHORIZED, message);
            String jsonString = JSON.toJSONString(jsonResult);

            httpServletResponse.setContentType("application/json; charset=UTF-8");
            PrintWriter writer = httpServletResponse.getWriter();
            writer.println(jsonString);
            writer.close();
        });

        //禁用“防止伪造的跨域攻击的防御机制”
        http.csrf().disable();

        /*
        * 请求授权
        * 各配置遵循“第一匹配原则”，如果某个请求被多个配置都可以匹配，以第一次匹配的为准
        * 在配置时，应该先配置更精准匹配的请求，再配置较模糊的
        * */
        http.authorizeRequests()
                .mvcMatchers("/**")/*匹配某些请求*/
                .permitAll()/*许可，即不需要认证即可访问*/
                .anyRequest()/*匹配任何请求，及任何请求，具体表现为：除了以上配置过的请求以外的其他请求*/
                .authenticated()/*需要已经通过认证*/
        ;

        // 当调用formLogin时，表示启用登录项与登出页
        //当尝试请求某个需要通过认证的资源，却还没有统统认证时
        //--  如果请用登出页，则会自动重定向到登出页
        //-- 如果未启用登录页，则会响应403错误
        //http.formLogin();
    }
}
